<?php 
/*
PS.
    最难懂的四件事:
        1.道士的符文
        2.医生的处方
        3.女人的心
        4.还有程序员的正则

正则表达式

简介：
    正则表达式（英语：Regular Expression，在代码中常简写为regex、regexp或RE），计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在很多文本编辑器里，正则表达式通常被用来检索、替换那些符合某个模式的文本。许多程序设计语言都支持利用正则表达式进行字符串操作。

历史：
    1940年，Warren McCulloch(沃伦.麦卡洛克)与Walter Pitts(沃尔特.皮茨)这两位神经生理方面的科学家,研究出了一种用数学方式来描述神经网络的新方法.将神经系统中的神经元描述成小而简单的自动控制元。
    
    1950年代，数学家Stephen Kleene(斯蒂芬·克莱尼)利用称之为“正则集合”的数学符号来描述此模型。
    
    之后,Unix之父:Ken Thompson(肯·汤普逊)将此符号系统引入编辑器QED，随后是Unix上的编辑器ed，并最终引入grep。自此以后，正则表达式被广泛地应用于各种Unix或类Unix系统的工具中。
    
    现在,你会在主流操作系统(*nix[Linux, Unix等]、Windows、HP、BeOS等)、主流的开发语言
    (delphi、Scala、PHP、C#、Java、C++、Objective-c、Swift、VB、Javascript、Ruby以及Python等)、数以亿万计的各种应用软件中，都可以看到正则表达式的身影.

[扩展1]
关于perl:
perl设计之初就是为了方便编写复杂高效的系统脚本，它也是应该最为广泛的脚本编程语言。
它在编程方面相当于瑞士军刀，对字符、文本文件处理能力很强，以前要求shell+sed+awk+C才能完成的任务，只需perl脚本就可以完成了。而且应用领域一直在拓宽，支持面向对象程序设计。


[扩展2]
“回车”（carriage return）VS  “换行”（line feed）
在计算机还没有出现之前，有一种叫做电传打字机（Teletype Model 33）的玩意，每秒钟可以打10个字符。但是它有一个问题，就是打完一行换行的时候，要用去0.2秒，正好可以打两个字符。要是在这0.2秒里面，又有新的字符传过来，那么这个字符将丢失。
于是，研制人员想了个办法解决这个问题，就是在每行后面加两个表示结束的字符。一个叫做“回车”，告诉打字机把打印头定位在左边界；另一个叫做“换行”，告诉打字机把纸向下移一行。
这就是“换行”和“回车”的来历，后来，计算机发明了，这两个概念也就被般到了计算机上。那时，存储器很贵，一些科学家认为在每行结尾加两个字符太浪费了，加一个就可以。于是，就出现了分歧。
Unix系统里，每行结尾只有“<换行>”，即“\n”；Windows系统里面，每行结尾是“<换行><回车>”，即“\n\r”；Mac系统里，每行结尾是“<回车>”。一个直接后果是，Unix/Mac系统下的文件在Windows里打开的话，所有文字会变成一行；而Windows里的文件在Unix/Mac下打开的话，在每行的结尾可能会多出一个^M符号。

关于换行符:
在文本处理中, CR, LF, CR/LF是不同操作系统上使用的换行符.
Dos和windows采用回车+换行CR/LF表示下一行, 
而UNIX/Linux采用换行符LF表示下一行，
苹果机(MAC OS系统)则采用回车符CR表示下一行.

CR用符号'\r'表示, 十进制ASCII代码是13, 十六进制代码为0x0D; 
LF使用'\n'符号表示, ASCII代码是10, 十六制为0x0A.

所以Windows平台上换行在文本文件中是使用 0d 0a 两个字节表示, 而UNIX和苹果平台上换行则是使用0a或0d一个字节表示.

一般操作系统上的运行库会自动决定文本文件的换行格式. 如一个程序在windows上运行就生成CR/LF换行格式的文本文件，而在Linux上运行就生成LF格式换行的文本文件.
在一个平台上使用另一种换行符的文件文件可能会带来意想不到的问题, 特别是在编辑程序代码时. 有时候代码在编辑器中显示正常, 但在编辑时却会因为换行符问题而出错.
 */


PHP正则
1.定界符
    ~!@#$%^&*(){}<>    /  #

2.原子
    是组成正则的最小单位,原子就是匹配一个字符
2.1 普通字符
    数字/字母下划线 0~9 A~Z a~z _
2.2 特殊字符
    使用特殊字符,需要转义才能正常使用
    '' "" / . * + ? | () & ^ \
    需要匹配\ 必须使用四根\来转义
2.3 非打印字符
    \f -- 分页符
    \r -- 回车符
    \n -- 换行符
    \t -- 制表符
    \v -- 垂直制表符
2.4 通用字符
    \d 匹配任意一个十进制数字[0~9]
    \D 匹配任意一个十进制数字以外的字符

    \s 匹配任意一个空白字符 [空格 tab \f\r\n\t\v]
    \S 匹配任意一个除了空白字符以外的任意一个字符

    \w 匹配任意一个数字/字母/下划线[0-9 a-z A-Z _]
    \W 匹配任意一个数字/字母/下划线以外的一个字符
    (打死我,大写取反)
2.5 原子表
    用中括号[]来表示自定义的原子,,在以上方案无法满足时使用
    [abc]  匹配原子表中的任意一个字符
    [^abc] 匹配除了原子表中的任意一个字符.

3.元字符
    用来修饰其前面的原子出现的次数或者位置
    !(元字符不能单独出现)
3.1 限定符
    *     匹配其前面的 原子出现 0次 1次 多次(不限次数,任意多次)
    +     匹配其前面的 原子出现 1次 多次(至少一次)
    ?     匹配其前面的 原子出现 0次 1次(至多一次)
    {n}   匹配其前面的 原子出现 正好n次
    {n,}  匹配其前面的 原子出现 至少n次
    {n,m} 匹配其前面的 原子出现 至少n次,至多m次
3.2 边界限制
    ^ 或 \A 匹配字符串必须以某个字符开始
    $ 或 \Z 匹配字符串必须以某个字符结束

    \b 单词边界
    \B 除了单词边界以外的部分

3.3 句号
    . 匹配任何一个字符,除了换行符(\n)
3.4 模式选择符
    | 在多个模式之间,选择匹配一个匹配到的那个模式
3.5 模式单元
    ()  把括号中的内容当作一个整体,当作一个大原子
    ()  子模式
3.6 后向引用 (最大99个)
    \1 \2 \3
    \\1 \\2 \\3
    $1 $2 $3
    用()标记的原子就是一个子模式,独立的单元,
    所有子模式匹配到的内容会被临时存储在临时缓存区的地方,以备后用
    
4.模式修正符
    必须放在定界符的外边,而且是右边
    i  不区分大小写
    m  视为多行
    s  视为一行
    x  模式中的空白忽略不记(除非已经被转义)
    U  非贪婪模式(默认就是贪婪模式)
    (我没事就下个大游戏)
    (i miss yoU)

PS.关于模式匹配的优先级
    1. \
    2. () (?:) (?=), []
    3. * + ? {n} {n,} {n,m}
    4. ^ $ \b \B \A \Z
    5.| 
*/

$str = "abcabcabcabcabcabc";
$regex = '/[abc]{3}/';
$regex = '/(abc){3}/';

$str = "abc123abc456abc789";
$regex = '/[abc]{3}/';
$regex = '/(abc)(123)\w+(789)/';

$str = "2008-08-08 08:08:08";
$regex = '/20(08)-\1-\1 \1:\1:\1/';

$str = "2008-08-08 20:08:08";
$regex = '/(20)(08)-\2-\2 \1:\2:\2/';

$str = "2008-08-08 11:08:08";
$regex = '/(\d{2})(\d{2})(-\2)\3\s\1(:\2)\4/';

$str = "2008-08-08 200808";
$regex = '/((20)(08))-\3-\3 \1\3/';

$str = "i love you xxx,xxx 你造吗?";
$regex = '/(?:i love you) (xxx),\1 你造吗?/';

$str = "aBc";
$regex = '/[abc]{3}/i';

$str = "aaaa\nbbbb\ncccc\ndddd";
$regex = '/.*/s';

$str = "ab";
$regex = '/a                     b/x';

$str = "<b>aaa</b><b>bbb</b><b>ccc</b>";
$regex = '/<b>.*<\/b>/U';

if (preg_match($regex, $str, $arr)) {
    echo '正则表达式<font size="5" color="green">'.htmlentities($regex).'</font>匹配字串<font size="5" color="green">'.$str.'</font>成功';
    echo '<pre>';
    print_r($arr);
    var_dump($arr);
} else {
    echo '正则表达式<font size="5" color="red">'.$regex.'</font>匹配字串<font size="5" color="red">'.$str.'</font>失败';
}





